package com.sojson.util.encryption.impl;

import com.sojson.constant.Constant;
import com.sojson.constant.ConstantByMap;
import com.sojson.util.StringUtil;
import com.sojson.util.encryption.Base64Util;
import com.sojson.util.encryption.EncryptionUtil;
import com.sojson.util.encryption.EncryptionUtilInterface;
import com.sojson.util.encryption.Md5Util;

/**
 * 加密工具类实现类
 * 
 * @author liu
 * @Date 2020-06-29 10:28:03
 * @Description
 *
 */
public class EncryptionUtilImpl implements EncryptionUtilInterface {

    private static EncryptionUtilImpl encryptionUtilsImpl;

    private EncryptionUtilImpl() {}

    /**
     * 不可逆的加密方法,MD5加密
     * 
     * @param inStr
     * @return
     * @throws Exception
     */
    @Override
    public String encryption(String inStr) throws Exception {
        return encryption(inStr, null);
    }

    /**
     * 不可逆的加密方法,MD5加密
     * 
     * @param inStr
     * @param key
     *            加密密钥
     * @return
     * @throws Exception
     */
    @Override
    public String encryption(String inStr, String key) throws Exception {
        byte[] inStrArray = inStr.getBytes(Constant.DEFAULT_ENCODING);
        if (isNotBlankObject(key)) {
            inStrArray = keyEncryption(inStrArray, key);
        }

        return Md5Util.encryptionToUpperCase(inStrArray);
    }

    /**
     * 可逆的加密方法,Base64加密
     * 
     * @param inStr
     * @return
     */
    @Override
    public String encryptionReversible(String inStr) {
        return encryptionReversible(inStr, null);
    }

    /**
     * 可逆的加密方法,Base64加密
     * 
     * @param inStr
     * @param key
     *            加密密钥
     * @return
     */
    @Override
    public String encryptionReversible(String inStr, String key) {
        byte[] bt = inStr.getBytes();
        if (isNotBlankObject(key)) {
            bt = keyEncryption(bt, key);
        }

        return Base64Util.encryption(bt);
    }

    /**
     * 解密方法,Base64解密
     * 
     * @param inStr
     * @return
     */
    @Override
    public String decryption(String inStr) {
        return decryption(inStr, null);
    }

    /**
     * 解密方法,Base64解密
     * 
     * @param inStr
     * @param key
     *            解密密钥
     * @return
     */
    @Override
    public String decryption(String inStr, String key) {
        byte[] bt = Base64Util.decryptionToByte(inStr);
        if (isNotBlankObject(key)) {
            bt = keyDecryption(bt, key);
        }
        return new String(bt);
    }

    /**
     * 解密方法,Base64解密
     * 
     * @param inStr
     * @return
     */
    @Override
    public byte[] decryption(byte[] inStr) {
        return decryption(inStr, null);
    }

    /**
     * 解密方法,Base64解密
     * 
     * @param inStr
     * @param key
     *            解密密钥
     * @return
     */
    @Override
    public byte[] decryption(byte[] inStr, String key) {
        byte[] bt = Base64Util.decryptionToByte(inStr);
        if (isNotBlankObject(key)) {
            bt = keyDecryption(bt, key);
        }
        return bt;
    }

    /**
     * 用key对字符串加密,原理: 字符串每个字符对key每个字符进行计算
     * 
     * @param inStr
     * @param key
     * @return
     */
    private byte[] keyEncryption(byte[] inStr, String key) {
        int keyLength = key.length();
        byte[] b = null;
        int charLength = inStr.length;

        // 字符长度小于key长度
        if (charLength < keyLength) {
            key = key.substring(0, charLength);
        } else if (charLength > keyLength) {
            // 字符长度大于key长度

            StringBuilder stringBuilder = new StringBuilder(key);
            // 字符长度减去key长度后剩余的长度
            int minusLenth = charLength - keyLength;
            // 剩余长度除以要拼接的密钥的长度,得出要拼接几次密钥
            int divide = minusLenth / EncryptionUtil.SUFFIX_KEY_LENTH;
            // 拼接密钥
            for (int j = 0; j < divide; j++) {
                stringBuilder.append(ConstantByMap.DEFAULT_KEY);
            }
            // 剩余长度余要拼接的密钥长度,得出拼完后还差几个字符
            int remainder = minusLenth % EncryptionUtil.SUFFIX_KEY_LENTH;
            // 拼接剩余字符
            if (remainder != 0) {
                stringBuilder.append(ConstantByMap.DEFAULT_KEY.substring(0, remainder));
            }
            key = stringBuilder.toString();
        }
        b = key.getBytes();
        // 字符串每个字符加上key对应的字符
        for (int i = 0; i < charLength; i++) {
            inStr[i] += b[i];
        }

        return inStr;
    }

    /**
     * 用key对字符串解密,原理: 字符串每个字符对key每个字符进行计算
     * 
     * @param inStr
     * @param key
     * @return
     */
    private byte[] keyDecryption(byte[] inStr, String key) {
        int keyLength = key.length();
        byte[] b = null;
        int charLength = inStr.length;

        // 字符长度小于key长度
        if (charLength < keyLength) {
            key = key.substring(0, charLength);
        } else if (charLength > keyLength) {
            // 字符长度大于key长度

            StringBuilder stringBuilder = new StringBuilder(key);
            // 字符长度减去key长度后剩余的长度
            int minusLenth = charLength - keyLength;
            // 剩余长度除以要拼接的密钥的长度,得出要拼接几次密钥
            int divide = minusLenth / EncryptionUtil.SUFFIX_KEY_LENTH;
            // 拼接密钥
            for (int j = 0; j < divide; j++) {
                stringBuilder.append(ConstantByMap.DEFAULT_KEY);
            }
            // 剩余长度余要拼接的密钥长度,得出拼完后还差几个字符
            int remainder = minusLenth % EncryptionUtil.SUFFIX_KEY_LENTH;
            // 拼接剩余字符
            if (remainder != 0) {
                stringBuilder.append(ConstantByMap.DEFAULT_KEY.substring(0, remainder));
            }
            key = stringBuilder.toString();
        }
        b = key.getBytes();
        // 字符串每个字符减去key对应的字符
        for (int i = 0; i < charLength; i++) {
            inStr[i] -= b[i];
        }

        return inStr;
    }

    // // 测试主函数
    // public static void main(String args[]) throws NoSuchAlgorithmException {
    // String key = "true";
    // EncryptionUtilImpl e = new EncryptionUtilImpl();
    // long currentTimeMillis = System.currentTimeMillis();
    // String s = new String(
    // "{\"rememberMe\":\"false\",\"username\":\"1\",\"password\":\"1\",\"cellphoneComputerMeanwhileOnline\":\"true\",\"onlineMaxNumber\":\"5\",\"morePlaceOnline\":\"false\",\"cellphoneOrComputer\":\"0\",\"data\":\"true\",\"key\":\"true\",\"date\":\""
    // + currentTimeMillis + "\"}");
    // System.out.println("原始:" + s);
    // System.out.println("不可逆加密的:" + e.encryption(s));
    // System.out.println("不可逆带key加密的:" + e.encryption(s, key));
    // String encryptionReversible = e.encryptionReversible(s);
    // System.out.println("可逆加密的:" + encryptionReversible);
    // String encryptionReversibleKey = e.encryptionReversible(s, key);
    // System.out.println("可逆带key加密的:" + encryptionReversibleKey);
    // System.out.println("可逆解密的:" + e.decryption(encryptionReversible));
    // System.out.println("可逆带key解密的:" + e.decryption(encryptionReversibleKey, key));
    // }

    /**
     * 判断一个对象是否不是空(空对象)
     * 
     * @param obj
     * @return
     */
    private boolean isNotBlankObject(Object obj) {
        return StringUtil.isNotBlankObject(obj);
    }

    /**
     * 判断一个对象是否是空(空对象)
     * 
     * @param obj
     * @return
     */
    private static boolean isBlankObject(Object obj) {
        return StringUtil.isBlankObject(obj);
    }

    public static EncryptionUtilImpl getInstances() {
        if (isBlankObject(encryptionUtilsImpl)) {
            encryptionUtilsImpl = new EncryptionUtilImpl();
        }
        return encryptionUtilsImpl;
    }

}